﻿using Algorithm.Check;
using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Algorithm.Check.ExtensionForCRC16;

namespace NewDevice.RS485
{
    /// <summary>
    /// 赫斯曼温度变送器控制类
    /// 提供基于Modbus协议的赫斯曼温度变送器通信功能
    /// </summary>
    public class ALT_HSM
    {
        /// <summary>
        /// 设备名称
        /// </summary>
        private string deviceName = "温度变送器";

        /// <summary>
        /// 串口通信对象
        /// </summary>
        private readonly SerialBase serial;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="bus">串口通信对象</param>
        public ALT_HSM(SerialBase bus)
        {
            this.serial = bus;
        }

        /// <summary>
        /// 读取Modbus寄存器数据
        /// </summary>
        /// <param name="slaveId">从机地址</param>
        /// <param name="address">寄存器起始地址</param>
        /// <param name="length">要读取的寄存器数量</param>
        /// <returns>读取到的寄存器数据</returns>
        /// <exception cref="Exception">当返回数据长度与预期不符时抛出异常</exception>
        private byte[] ReadRegister(int slaveId, int address, int length)
        {
            // 构造Modbus读取寄存器命令
            byte[] cmd = new byte[] {
                (byte)slaveId,
                0x03, // 功能码:读取保持寄存器
                (byte)((address & 0xff00) >> 8), // 寄存器地址高字节
                (byte)(address & 0xff), // 寄存器地址低字节
                (byte)((length & 0xff00) >> 8), // 寄存器数量高字节
                (byte)(length & 0xff), // 寄存器数量低字节
            };

            // 添加CRC16校验
            cmd = cmd.WithCRC16(CRC16Type.Modbus).ToArray();

            // 设置设备名称并发送命令
            serial.deviceName = deviceName;
            byte[] recv = serial.SendBytesAndWaitResponse(cmd, ReceivedDataCheck.FuncModbusCRC16Check);

            // 验证返回数据长度
            if (length * 2 != recv[2])
            {
                throw new Exception($"[{deviceName}] ReadRegister错误，返回数据与长度异常");
            }

            // 返回有效数据部分(去除Modbus协议头)
            return recv.Skip(3).Take((recv[2])).ToArray();
        }

        /// <summary>
        /// 读取温度值
        /// </summary>
        /// <param name="slaveId">从机地址</param>
        /// <returns>当前温度值(浮点数)</returns>
        public float GetTemperature(int slaveId)
        {
            // 从0x0408地址读取2个寄存器(4字节)的温度数据
            var byteTemp = ReadRegister(slaveId, 0x0408, 02);

            // 反转字节顺序(Modbus为大端模式)
            Array.Reverse(byteTemp);

            // 将字节数组转换为浮点数
            var temp = BitConverter.ToSingle(byteTemp, 0);

            // 记录调试日志
            Mylog.Info(message: $"{deviceName} 温度=[{temp}] ", deviceName: deviceName);

            return temp;
        }

        /// <summary>
        /// 检查设备是否在线
        /// </summary>
        /// <param name="slaveId">从机地址，默认为1</param>
        /// <returns>设备是否在线</returns>
        public bool IsDeviceOnline(int slaveId = 1)
        {
            try
            {
                // 尝试读取温度值来检测设备是否在线
                var val = GetTemperature(slaveId);
                return true;
            }
            catch (Exception ex)
            {
                // 记录错误日志
                Mylog.Error(message: $"{deviceName}不在线,{ex.Message}", ex: ex);
                return false;
            }
        }
    }
}